Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.

...powered by www.netzwerkartist.de...

 << zurück
Visual C# 2005 von Andreas Kühnel
Das umfassende Handbuch
Buch: Visual C# 2005

Visual C# 2005
1.320 S., mit 2 CDs, 59,90 Euro
Galileo Computing
ISBN 3-89842-586-X
gp Kapitel 11 Multithreading und asynchrone Methodenaufrufe
  gp 11.1 Prozesse und Threads
    gp 11.1.1 Threadzustände und Prioritäten
    gp 11.1.2 Einsatz von mehreren Threads
  gp 11.2 Die Entwicklung einer Multithread-Anwendung
    gp 11.2.1 Die Klasse »Thread«
    gp 11.2.2 Threadpools nutzen
  gp 11.3 Die Synchronisation von Threads
    gp 11.3.1 Unsynchronisierte Threads
    gp 11.3.2 Der »Monitor« zur Synchronisation
    gp 11.3.3 Das Synchronisationsobjekt »Mutex«
    gp 11.3.4 Das Attribut »MethodImpl«
  gp 11.4 Asynchrone Methodenaufrufe
    gp 11.4.1 Asynchroner Methodenaufruf
    gp 11.4.2 Asynchroner Aufruf mit Rückgabewerten
    gp 11.4.3 Eine Klasse mit asynchronen Methodenaufrufen

Kapitel 11 Multithreading und asynchrone Methodenaufrufe


Galileo Computing

11.1 Prozesse und Threaddowntop

Stellen Sie sich eine beliebige Anwendung vor, die in der Lage ist, Mails zu versenden. Das Versenden kann, wenn die Mail mehrere größere Anhänge hat, durchaus einen längeren Zeitraum in Anspruch nehmen. Während des Versendens wird eine Sanduhr angezeigt, und der Anwender kann nicht mit der Applikation weiterarbeiten. Erstrebenswert ist es, dem Anwender eine Anwendung auszuliefern, die ohne die Darstellung der Sanduhr auskommt. Dazu wäre nur eine Applikation in der Lage, die das Multithreading beherrscht. Mit einer solchen Anwendung könnte der Benutzer weiterarbeiten, während (scheinbar) gleichzeitig die Mail verschickt wird.

Die Entgegennahme der Benutzereingabe und das Versenden der Mail sind zwei Operationen, die in einer multithreading-fähigen Anwendung voneinander unabhängig sind und innerhalb eines einzigen Prozesses ablaufen. Beide Operationen können dabei dieselben Daten benutzen. Jeder Operation wird dazu ein eigener Thread zugeordnet. Ein Thread ist eine Ausführungseinheit und besteht aus einer kontinuierlichen Abfolge von Anweisungen. Sie werden weiter unten in den Beispielen noch sehen, wie das zu verstehen ist.

Jeder gestarteten Anwendung ist ein Prozess zugeordnet, in dem mindestens ein Thread existiert. Somit ist ein Thread die kleinste Ausführungseinheit und gehört im Umkehrschluss grundsätzlich immer zu einem Prozess. Wird der letzte Thread eines Prozesses zerstört, wird die Laufzeit der Anwendung beendet.

Eine Ein-Prozessor-Maschine vorausgesetzt, kann zu einem gegebenen Zeitpunkt nur ein Thread von der CPU bearbeitet werden. Stehen mehrere Threads derselben oder auch unterschiedlicher Anwendungen zur Ausführung in einer Warteschlange, erfolgt der Austausch der Threads in der CPU in sehr kleinen Zeitintervallen. Einem Anwender fällt das nicht auf – aus seiner Sicht erscheint es so, als würde die Ausführung gleichzeitig erfolgen.

Die gesamte Zeit, über die ein Mikroprozessor verfügt, veranschaulicht man sich häufig durch eine Kreisfläche, auch Zeitscheibe genannt. Die Zeitscheibe wird in eine bestimmte Anzahl von Kreisausschnitten aufgeteilt – entsprechend der Anzahl der aktiven Threads. Jeder Ausschnitt, der vom Betriebssystem und vom Prozessortyp abhängt, beschreibt eine gleich große Bogenlänge. Die Bogenlänge stellt die Prozessorzeit dar, die dem Thread zur Verfügung steht. Eine Komponente des Systems, der Scheduler, ist für die Zuteilung einer Zeitscheibeneinheit an einen wartenden Thread verantwortlich.

Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 11.1   Die Zeitscheibe eines Mikroprozessors

In Abbildung 11.1 stellt die CPU jedem Thread 20 Millisekunden zur Verfügung, gleichzeitig sind acht Threads gleichberechtigt aktiv. Der Prozess A ist daran mit vier Threads beteiligt, der Prozess B mit zwei und die Prozesse C und D mit je einem. Somit beschreibt die Zeitscheibe eine Gesamtzeit von 160 Millisekunden. Falls sich an der Bedingung nichts ändert, gelangt jeder Thread alle 0,16 Sekunden zur Ausführung, zu der ihm insgesamt 20 Millisekunden zur Verfügung stehen – einschließlich des Ladens der Daten aus dem Stack in die Register der CPU und des Entladens, wenn die Zeit für den Thread abgelaufen ist.

Im Kontext jedes Threads sind alle Informationen enthalten, um die unterbrochene Ausführung zu einem späteren Zeitpunkt wieder problemlos aufnehmen zu können. Dazu gehören die Inhalte der CPU-Register zum Zeitpunkt des Verlassens des Prozessors sowie alle Informationen, die den Zustand des Threads beschreiben.


Galileo Computing

11.1.1 Threadzustände und Prioritätedowntop

Wartende, bereite und laufende Threads

Jeder Thread kann sich in einem von drei möglichen Zuständen befinden:

gp  wartend (waiting)
gp  bereit (ready)
gp  laufend (running)

Ein laufender Thread befindet sich aktuell im Prozessor und wird ausgeführt. Ein Prozessor kann zu einem gegebenen Zeitpunkt immer nur einen Thread bearbeiten. Nach Ablauf der zugestandenen Zeitspanne muss der laufende Thread die CPU räumen. Er reiht sich wieder in die Warteschlange auf der Zeitscheibe ein und hofft darauf, dass ihm möglichst schnell wieder Prozessorzeit zugeteilt wird.

Die Threads, die in der Warteschlange stehen, werden als bereit bezeichnet. Nur einem bereiten Thread kann ein Zeitquantum der CPU zugestanden werden.

Es gibt aber auch Threads, die während ihrer Ausführung freiwillig den Prozessor räumen und auch danach zunächst nicht mehr willens sind, sich in die Warteschlange der bereiten Threads einzuordnen. Diese Threads werden als wartend bezeichnet. Ein wartender Thread muss den Anstoß von einem anderen Thread bekommen, um in den bereiten Zustand überführt zu werden.

Bezogen auf einen Prozessor kann sich zu einem gegebenen Zeitpunkt nur ein Thread im laufenden Zustand befinden. Die anderen Threads sind entweder bereit oder wartend. Der aktuell ausgeführte Thread muss unter gewissen Bedingungen den Prozessor aufgeben:

gp  Das ihm zugestandene Zeitquantum ist abgelaufen.
gp  Der Thread muss auf ein anderes Objekt oder eine Benachrichtigung warten. Er tritt in den Zustand wartend ein.
gp  Ein anderer Thread mit einer höheren Priorität befindet sich in der Warteschlange.

Während die beiden zuerst aufgeführten Punkte aufgrund der vorherigen Ausführungen einleuchtend sein sollten, ist der dritte neu.

Thread-Prioritäten

Jedem Thread wird eine bestimmte Priorität zugeordnet. Stehen mehrere Threads in der Warteschlange, erhält derjenige Prozessorzeit, dessen Priorität am höchsten ist. Windows kennt die Prioritätsstufen 1 bis 31, die allerdings nicht alle genutzt werden. Viele Systemthreads laufen mit einer höheren Priorität als die Threads »normaler« Anwendungen. Der Prioritätszuordnung eines Threads und den daraus resultierenden Konsequenzen bei der Prozessorzuteilung kommt eine sehr große Bedeutung zu. Gäbe es die Zuordnung einer Priorität nicht, wäre es unter anderem nicht möglich, aus einer laufenden Windows-Anwendung heraus eine andere zu aktivieren. Das System fängt nämlich in einem Thread hoher Priorität den Mausklick auf das Fenster einer inaktiven Anwendung ab, ordnet die Mauszeigerposition dem direkt darunter liegenden Fenster zu und aktiviert es.

Auch normale Anwendungsthreads können bei Bedarf höher eingestuft werden. Damit kann man erreichen, dass Aufgaben, die Vorrang vor anderen haben sollen, nicht gleichberechtigt mit den anderen Threads behandelt werden, sondern bevorzugt. Umgekehrt kann die Priorität eines Threads auch verringert werden, um ihn einerseits bereitzuhalten, aber andererseits nur in bestimmten Situationen zur Ausführung zu bringen, möglicherweise auch erst nach vorheriger Erhöhung der Priorität.

Einen Thread mit niedriger Priorität haben Sie in Kapitel 4 kennen gelernt: Es ist der Thread des Garbage Collectors. Dieser erhält erst dann Prozessorzeit, wenn keine andere Ausführungseinheit die CPU beansprucht oder die Ressourcen knapp werden. Tritt die letztgenannte Situation ein, wird die Priorität des Garbage Collectors angehoben, damit die Speicherbereinigung ihre Arbeit verrichtet.

Ein Thread, dessen Zeit auf der Zeitscheibe abgelaufen ist, wird als bereit markiert und sichert den Zustand der Daten im Stack. Danach sucht das Betriebssystem nach dem Thread, der sowohl als bereit markiert ist und gleichzeitig die höchste Priorität besitzt. Befinden sich mehrere bereite Threads auf derselben Prioritätsstufe, weist der Scheduler dem in der Reihenfolge stehenden Thread den Prozessor zu.


Galileo Computing

11.1.2 Einsatz von mehreren Threads  toptop

Eine Multithreading-Anwendung zu schreiben, ist nicht einfach und birgt immer die latente Gefahr von Fehlerquellen. Eine der größten ist der gleichzeitige Zugriff mehrerer Komponenten auf eine gemeinsame Ressource. Wartet zum Beispiel ausnahmslos jede der beteiligten Komponenten auf die Antwort der anderen, wäre ein Deadlock die Folge – die Anwendung kann nicht mehr weiterarbeiten und hängt sich auf. Wir können in diesem Kapitel nicht alle Aspekte erörtern, die in diesem Zusammenhang von Bedeutung sind. Sie sollten aber immer daran denken, dass mit steigender Anzahl der Threads das Gefahrenpotenzial exponential steigt, die Komplexität der Anwendung drastisch zunimmt und der Ablauf der Anwendung nur noch äußerst schwierig nachzuvollziehen ist.

Trotz der Schwierigkeiten, die sich bei der Entwicklung einer Multithreading-Anwendung ergeben, gibt es eine Reihe von Situationen, in denen der Einsatz mehrerer Threads sinnvoll ist. Meistens handelt es sich um Operationen, die generell eine längere Zeitspanne für ihre Ausführung benötigen, z.B. bei der Kommunikation mit anderen Rechnern über das Netzwerk oder bei Tasks, die als zeitkritisch eingestuft werden müssen.

 << zurück
  
  Zum Katalog
Zum Katalog: Visual C# 2005
Visual C# 2005
bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: Fortgeschrittene Programmierung mit Visual C# 2005






 Fortgeschrittene
 Programmierung
 mit Visual C# 2005


Zum Katalog: Einstieg in Visual C# 2005






 Einstieg in
 Visual C# 2005


Zum Katalog: Einstieg in Visual Basic 2005






 Einstieg in
 Visual Basic 2005


Zum Katalog: Visual Basic 2005






 Visual Basic 2005


Zum Katalog: Java ist auch eine Insel






 Java ist auch eine
 Insel


Zum Katalog: Konzepte und Lösungen für Microsoft-Netzwerke






 Konzepte und
 Lösungen für
 Microsoft-Netzwerke


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo








Copyright © Galileo Press 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de